#ifndef INSTANCE_H_
#define INSTANCE_H_

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include "config.h"

/**
 * Maximum number of instances that can be created at the same time
 */
#define MAX_INSTANCES 512


typedef struct Instance {
	char callerObject[MAX_VAR_LEN];
	char varName[MAX_VAR_LEN];
	pid_t pid;
	int pipe[2];
} Instance;

/**
 * Static structure that stores all the instances created
 */
typedef struct InstanceQueue {
  int index;
  Instance instances[MAX_INSTANCES];
} InstanceQueue;

/**
 * Associates a varname to a bloc id
 */
typedef struct InstanceMemory {
	char varName[MAX_VAR_LEN];
	int blocReturnId;
	int freed;
} InstanceMemory;


typedef struct InstanceMemoryQueue {
	int index;
	InstanceMemory queue[MAX_INSTANCES];	
} InstanceMemoryQueue;



/**
 * Global instance queue
 */
InstanceQueue queue;

/**
 * Global containers that associates a var name to a bloc return id
 */
InstanceMemoryQueue instanceMemQueue;

/**
* Initialize the queue
*/
void initQueue(InstanceQueue* queue);

/**
 * Initialize the instance structure
 */
void initInstance(Instance* ins);

/**
 * Initialize the instance structure
 */
void initInstanceMemory(InstanceMemory* ins);

/**
 * Prints an instance memory information
 */
void printInstanceMemory(InstanceMemory instance);

/**
 * Prints an instance
 */
void printInstance(Instance instance);

/**
* Checks whether an instance is defined
* Instance is considered as undefined if its pid field value is set to -1
*/
int existInstance(Instance ins);

/**
 * Retrieves an instance memory from the instance memory queue
* @param inscmp a pointer to a function that compares two instances. If the comparison of a and b returns 1 then getInstance will retrieve the current instance
 * @return the instance memory, NULL if it couldn't be found
 */
InstanceMemory* getInstanceMemory(InstanceMemory* ins, int (*inscmp)(InstanceMemory a, InstanceMemory b));


/**
 * Pushes a new instance in queue
 * @param queue a pointer to the structure containing the list of instances
 * @param ins the instance to push
 */
void pushInstance(InstanceQueue* queue, Instance ins);

/**
 * Pops the last element off the queue
 * @param queue a pointer to the structure containing the list of instances
 * @return the instance popped or NULL
 */
Instance* popInstance(InstanceQueue* queue);

/**
* Retrieves an instance from the queue
* @param queue a pointer to the structure containing the list of instance
* @param ins, instance to compare to queue instances 
* @param inscmp a pointer to a function that compares two instances. If the comparison of a and b returns 1 then getInstance will retrieve the current instance
* @return the instance or NULL
*/
Instance* getInstanceFromName(InstanceQueue* queue, Instance* ins, int (*inscmp)(Instance a, Instance b));

/**
 * Function used to compare instances
 * @param a the first instance
 * @param b the second instance
 * @return 0 if the two instances are equals, negative number otherwise
 */
int compareInstanceByCallerObjectName(Instance a, Instance b);


/**
 * Function used to compare instances
 * @param a the first instance
 * @param b the second instance
 * @return 0 if the two instances are equals, negative number otherwise
 */
int compareInstanceByVarName(Instance a, Instance b);


/**
 * Function used to compare instances by pid
 * @param a the first instance
 * @param b the second instance
 * @return 0 if the two instances are equals, negative number otherwise
 */
int compareInstanceByPid(Instance a, Instance b);




/**
 * Function used to compare instances memory by name
 * @param a the first instance
 * @param b the second instance
 * @return 0 if the two instances are equals, negative number otherwise
 */
int compareInstanceMemByVarName(InstanceMemory a, InstanceMemory b);


/**
 * Function used to compare instances memory by bloc id
 * @param a the first instance
 * @param b the second instance
 * @return 0 if the two instances id are equals, negative number otherwise
 */
int compareInstanceMemById(InstanceMemory a, InstanceMemory b);


#endif /* INSTANCE_H_ */

